Loading a RichTextBox from an RTF file using binding or a RichTextFile control
Sometimes you have a rich text document that exists as an actual file and you simply want to load the file and display it.
My exact use cases are these:
- Load and display a rich text file in read only mode
- The links must open inside a browser and not in the application
I like to use MVVM, so my goal is to use binding to pass in the file name. Unfortunately the RichTextBox class is not designed to bind to a file name. However, extending this control to have this functionality is quite easy.
RichTextFile extending RichTextBox
Here is my new class. I have extended RichTextBox with four additional items in a new derived class called RichTextFile.
- Added a String Property called File.
- Added a DependecyProperty called FileProperty
- Added a PropertyChangedCallback function called OnFileChanged
- Added a ReadFile function that reads a .rtf file into a FlowDocument
- Added a Constructor that adds a handler for the Hyperlink.RequestNavigateEvent.
- Added a Property called OpenLinksInBrowser.
using System.Diagnostics; using System.IO; using System.Windows.Documents; namespace System.Windows.Controls { internal class RichTextFile : RichTextBox { public RichTextFile() { AddHandler(Hyperlink.RequestNavigateEvent, new RoutedEventHandler(HandleHyperlinkClick)); } private void HandleHyperlinkClick(object inSender, RoutedEventArgs inArgs) { if (OpenLinksInBrowser) { Hyperlink link = inArgs.Source as Hyperlink; if (link != null) { Process.Start(link.NavigateUri.ToString()); inArgs.Handled = true; } } } #region Properties public bool OpenLinksInBrowser { get; set; } public String File { get { return (String)GetValue(FileProperty); } set { SetValue(FileProperty, value); } } public static DependencyProperty FileProperty = DependencyProperty.Register("File", typeof(String), typeof(RichTextFile), new PropertyMetadata(OnFileChanged)); private static void OnFileChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { RichTextFile rtf = d as RichTextFile; if (rtf == null) return; ReadFile(rtf.File, rtf.Document); } #endregion #region Functions private static void ReadFile(string inFilename, FlowDocument inFlowDocument) { if (System.IO.File.Exists(inFilename)) { TextRange range = new TextRange(inFlowDocument.ContentStart, inFlowDocument.ContentEnd); FileStream fStream = new FileStream(inFilename, FileMode.Open, FileAccess.Read, FileShare.Read); range.Load(fStream, DataFormats.Rtf); fStream.Close(); } } #endregion } }
You can use this new object to load a .rtf file quite easily. I am going to show you how I am succeeding in my two use cases using both a regular WPF Application and a WPF Navigation Application.
Part 1 – Using the RichTextFile class in a WPF Application
Use Case 1 – Loading a rich text file
Create a new WPF Application in Visual Studio.
Add the above RichTextFile object to the project.
Add an xmlns reference to our new object. Then add our new object. Notice in our new object that we set IsReadOnly=”True” but we also set IsDocumentEnabled=”True”. This allows for clicking a link even though the document is read only.
<Window x:Class="RichTextFileTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:controls="clr-namespace:System.Windows.Controls"> <Grid> <controls:RichTextFile File="{Binding File}" IsReadOnly="True" IsDocumentEnabled="True" /> </Grid> </Window>
Code Behind
using System; using System.Diagnostics; using System.Windows; using System.Windows.Documents; namespace RichTextFileTest { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Example example = new Example() { File = "File.rtf" }; DataContext = example; } } public class Example { public String File { get; set; } } }
Now the first use case is complete, the rich text file is loading into the RichTextFile control and is visible in the application. However, the second use case is incomplete as clicking the link does nothing.
Use Case 2 – Getting the links to open in a browser
The links can easily made to open in a browser now by simply setting OpenLinksInBrowser=”True” on the RichTextFile object.
<Window x:Class="RichTextFileTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:controls="clr-namespace:System.Windows.Controls"> <Grid> <controls:RichTextFile File="{Binding File}" IsEnabled="True" IsReadOnly="True" IsDocumentEnabled="True" OpenLinksInBrowser="True"/> </Grid> </Window>
The links should now be opening in your browser.
Here is the sample project that demonstrates this.
RichTextFileTest.zip
Thanks was very useful and good article.
Very handy article, thanks. Now all I have to figure out is how to hook this up to a DatGrid DataTemplate so that the save/load is called when the row enters & exits edit mode...
[...] Previously, I discussed loading a rich text file in a regular WPF Application in this post: Loading a RichTextBox from an RTF file using binding or a RichTextFile control [...]